#include "MySqlHintStatement.h"
#include "../../../../../utils/instanceof.h"
#include "../../../../../utils/listTran.h"
#include "../../../../SQLUtils.h"
#include "../../../../visitor/SQLASTVisitor.h"
#include "../../visitor/MySqlASTVisitor.h"
#include "../../../../ast/SQLObject.h"

MySqlHintStatement::MySqlHintStatement()
{
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  hintStatements = std::make_shared<std::list<SQLStatement_ptr>>();
}

void MySqlHintStatement::accept0(SQLASTVisitor_ptr visitor)
{
  // if (instanceof<SQLASTVisitor,H2ASTVisitor>(visitor)  )
  // {
  //   return;
  // }
  MySqlStatementImpl::accept0(visitor);
}

void MySqlHintStatement::accept0(MySqlASTVisitor_ptr visitor)
{
  // if (visitor->visit(this))
  // {
  SQLObject_list_ptr tmp = ListTran::tran_class<SQLCommentHint, SQLObject>(this->hints);
  SQLASTVisitor_ptr tmp1 = std::dynamic_pointer_cast<SQLASTVisitor>(visitor);
  acceptChild(tmp1, tmp);
  // }
  // visitor->endVisit(this);
}

SQLCommentHint_list_ptr MySqlHintStatement::getHints()
{
  return hints;
}

void MySqlHintStatement::setHints(SQLCommentHint_list_ptr hints)
{
  this->hints = hints;
}

int MySqlHintStatement::getHintVersion()
{
  if (hints->size() != 1)
  {
    return -1;
  }

  auto it_hints = hints->begin();
  std::advance(it_hints, 0);
  SQLCommentHint_ptr hint = (*it_hints);

  string_ptr text = hint->getText();
  if (text->length() < 7)
  {
    return -1;
  }

  char c0 = text->at(0);
  char c1 = text->at(1);
  char c2 = text->at(2);
  char c3 = text->at(3);
  char c4 = text->at(4);
  char c5 = text->at(5);
  char c6 = text->at(6);

  if (c0 != '!')
  {
    return -1;
  }

  if (c1 >= '0' &&
      c1 <= '9' &&
      c2 >= '0' &&
      c2 <= '9' &&
      c3 >= '0' &&
      c3 <= '9' &&
      c4 >= '0' &&
      c4 <= '9' &&
      c5 >= '0' &&
      c5 <= '9' &&
      c6 == ' ')
  {
    return (c1 - '0') * 10000 + (c2 - '0') * 1000 + (c3 - '0') * 100 + (c4 - '0') * 10 + (c5 - '0');
  }

  return -1;
}

SQLStatement_list_ptr MySqlHintStatement::getHintStatements()
{
  SQLStatement_list_ptr empty_list = std::make_shared<std::list<SQLStatement_ptr>>();
  if (!hintStatements->empty())
  {
    return hintStatements;
  }

  if (hints->size() != 1)
  {
    return empty_list;
  }

  auto it_hints = hints->begin();
  std::advance(it_hints, 0);
  SQLCommentHint_ptr hint = (*it_hints);

  string_ptr text = hint->getText();
  if (text->length() < 7)
  {
    return empty_list;
  }

  char c0 = text->at(0);
  char c1 = text->at(1);
  char c2 = text->at(2);
  char c3 = text->at(3);
  char c4 = text->at(4);
  char c5 = text->at(5);
  char c6 = text->at(6);
  if (c0 != '!')
  {
    return empty_list;
  }

  int start;
  if (c1 == ' ')
  {
    start = 2;
  }
  else if (c1 >= '0' &&
           c1 <= '9' &&
           c2 >= '0' &&
           c2 <= '9' &&
           c3 >= '0' &&
           c3 <= '9' &&
           c4 >= '0' &&
           c4 <= '9' &&
           c5 >= '0' &&
           c5 <= '9' &&
           c6 == ' ')
  {
    start = 7;
  }
  else
  {
    return empty_list;
  }

  string_ptr hintSql = make_string_ptr(text->substr(start));
  hintStatements = SQLUtils::parseStatements(hintSql, dbType);
  return hintStatements;
}
